import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { FontLoader, Font } from  'three/examples/jsm/loaders/FontLoader.js';
import Stats from 'three/examples/js/libs/stats.min.js';
class starThreejs {
    constructor(config) {
        this.config=config;
        this.config['t']=THREE;
        this.config['scene']=new THREE.Scene();
        this.addHelper(this.config.helper);
        this.addPoint(this.config.point);
        this.addAmbient(this.config.ambient);
        this.addCamera(this.config.camera);
        this.addElements(this.config.groups);
        this.addElements(this.config.sensors);
        this.addLabel(this.config.labels);
        // this.addText();
        this.getTextCanvas2();
        this.addAnimation(this.config.clips);
        this.addRenderer(this.config.render);
        this.addControl();

    }
    addHelper(helper){
        if(!!helper){
            if(!!helper.plane){
                let plane = new this.config.t.Plane( new THREE.Vector3( 1, 0, 0 ), 3 );
                this.config.scene.add( new this.config.t.PlaneHelper( plane, 500, 0xffff00 ) );
            };
            if(!!helper.camera){
                this.config.scene.add(new this.config.t.CameraHelper(camera));
            };
            if(!!helper.axes){//用于简单模拟3个坐标轴的对象.红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.
                this.config.scene.add(new this.config.t.AxesHelper( 500 ));
            }
        }
    }
    /**
     * 点光源
     * @type {PointLight|PointLight}
     */
    addPoint(points){
        points.map(p=>{
            let point=new this.config.t.PointLight(p.c);
            point.position.set(p.x,p.y,p.z);
            this.config.scene.add(point);
        })
    }
    /**
     * 环境光
     * @type {AmbientLight|AmbientLight}
     */
    addAmbient(ambient){
        this.config.scene.add(new this.config.t.AmbientLight(ambient.c))
    }
    /**
     * 创建相机对象
     * @type {OrthographicCamera|OrthographicCamera}
     */
    addCamera(item){
        let s=this.config.info.s;
        let k=this.config.info.width/this.config.info.height;
        if(item.type==='OrthographicCamera'){
            let camera=new THREE.OrthographicCamera(-s*k,s*k,s,-s,item.n,item.f);
            camera.position.set(item.x,item.y,item.z);
            camera.lookAt(this.config.scene.position);
            this.config.scene.add(camera);
            this.config['cameraObject']=camera;
        }
    }
    addElements(groups){
        Object.keys(groups).map(group=>{
            let groupObject = new this.config.t.Group();
            groupObject.name=group;
            Object.keys(groups[group]).map(element=>{
                let gObject=null;
                let mObject=null;
                if(groups[group][element].gType==='box'){
                    gObject=new this.config.t.BoxGeometry(groups[group][element].xl,groups[group][element].yl,groups[group][element].zl);
                }
                if(groups[group][element].gType==='cylinder'){
                    gObject=new this.config.t.CylinderGeometry(groups[group][element].tr,groups[group][element].br,groups[group][element].hl,groups[group][element].segment);
                }
                if(groups[group][element].gType==='sphere'){
                    gObject=new this.config.t.SphereGeometry(groups[group][element].r,groups[group][element].s1,groups[group][element].s2);
                }
                if(groups[group][element].mType==='lambert'){
                    mObject=new this.config.t.MeshPhongMaterial({
                        color:groups[group][element].c,
                        specular:0xffffff,
                        shininess:80
                    })
                }
                let mesh=new this.config.t.Mesh( gObject, mObject );
                mesh.position.set(groups[group][element].x,groups[group][element].y,groups[group][element].z);
                if(!!groups[group][element].rx){
                    mesh.rotateX(groups[group][element].rx)
                }
                if(!!groups[group][element].ry){
                    mesh.rotateY(groups[group][element].ry)
                }
                if(!!groups[group][element].rz){
                    mesh.rotateZ(groups[group][element].rz)
                }
                mesh.name=group+'_'+element;
                groupObject.add( mesh );
            })
            this.config.scene.add( groupObject );
        })
    }
    addLabel(labels){
        let _this=this;
        Object.keys(labels).map(label=>{
            let gObject=null;
            let mObject=null;
            if(labels[label].gType==='plane'){
                gObject=new this.config.t.PlaneGeometry(labels[label].w,labels[label].h);
            }
            if(labels[label].mType==='image'){
                mObject=new _this.config.t.MeshBasicMaterial({
                    color: 'white',//labels[label].c,
                    side: THREE.DoubleSide,
                    map:new THREE.TextureLoader().load(this.getTextCanvas(labels[label].w,labels[label].h,labels[label].c,labels[label].t)),
                    opacity: 0.5,
                    // transparent:true
                })
                let mesh=new _this.config.t.Mesh( gObject, mObject )
                mesh.position.set(labels[label].x,labels[label].y,labels[label].z);
                if(!!labels[label].rx){
                    mesh.rotateX(labels[label].rx)
                }
                if(!!labels[label].ry){
                    mesh.rotateY(labels[label].ry)
                }
                if(!!labels[label].rz){
                    mesh.rotateZ(labels[label].rz)
                }
                mesh.name='label_'+label;
                _this.config.scene.add( mesh );
            }
        })
    }
    addAnimation(clips){
        this.config['mixers']=[];
        this.config['animations']=[];
        this.config['mixer']=new this.config.t.AnimationMixer(this.config.scene);
        Object.keys(clips).map(key=>{
            let anim=new this.config.t.KeyframeTrack(clips[key].key,clips[key].times,clips[key].values);
            let clip=new this.config.t.AnimationClip('default',clips[key].duration,[anim]);
            let animation=this.config.mixer.clipAction(clip);
            animation.play();
        })
    }
    /**
     * 创建渲染器对象
     * @type {WebGL1Renderer|WebGL1Renderer}
     */
    addRenderer(render){
        let renderer=new this.config.t.WebGL1Renderer({antialias: true});
        renderer.setSize(this.config.info.width,this.config.info.height);
        renderer.setClearColor(render.clearColor,render.opacity);
        this.config.info.el.appendChild(renderer.domElement);
        this.config['renderer']=renderer;
        let clock=new this.config.t.Clock();
        this.myRender=()=>{
            requestAnimationFrame(this.myRender);
            this.config.mixer.update(clock.getDelta())
            renderer.render(this.config.scene,this.config.cameraObject);
        };
        this.myRender();
    }
    addControl(){
        let controls=new OrbitControls(this.config.cameraObject,this.config.renderer.domElement);
        controls.addEventListener('change',this.myRender);
        this.config.renderer.domElement.addEventListener(
            "click",e=>{
                //获取raycaster和所有模型相交的数组，其中的元素按照距离排序，越近的越靠前
                let intersects = this.getIntersects(event);
                //获取选中最近的Mesh对象
                //instance坐标是对象，右边是类，判断对象是不是属于这个类的
                if (intersects.length !== 0 && intersects[0].object.type === 'Mesh') {
                    let selectObject = intersects[0].object;
                    //changeMaterial(selectObject)
                    let name=!!selectObject.parent?selectObject.parent.name:selectObject.name;
                    alert(name)
                    console.log(selectObject)
                } else {
                    console.log('未选中 Mesh!');
                }
            })
    }
    addText(){
        let text='furnace';

        let loader = new FontLoader();
        let _this=this;
        loader.load("three/examples/fonts/helvetiker_bold.typeface.json", function (res) {
            let geometry = new THREE.TextGeometry(`${text}`, {
                font: res,          // 字体格式
                size: 13,           // 字体大小
                height: 1,          // 字体深度
                curveSegments: 11,  // 曲线控制点数
                bevelEnabled: true, // 斜角
                bevelThickness: 0.1,  // 斜角的深度
                bevelSize: 1,       // 斜角的大小
                bevelSegments: 1    // 斜角段数
            });
            let mat = new THREE.MeshPhongMaterial({
                color: "white",
                opacity: 0.8,
                shininess: 1,
            });
            let mesh = new THREE.Mesh(geometry, mat);
            mesh.rotation.y = -Math.PI / 2
            mesh.position.set(-151, 150 - 40 * index, 15.1);
            _this.config.scene.add(mesh);
        })
    }
    getTextCanvas(w,h,c,text){
        //用canvas生成图片
        let canvas = document.createElement("canvas");
        let ctx = canvas.getContext('2d')
        canvas.width = w*300
        canvas.height = h*300
        //制作矩形
        ctx.fillStyle = c;
        ctx.fillRect(0, 0, w*300, h*300)
        //设置文字
        ctx.fillStyle = "white";
        ctx.font = 'normal 1500px "楷体"'
        ctx.fillText(text, w*20, h*300/2)

        //生成图片
        let url = canvas.toDataURL('image/png');
        return url;
    }
    getTextCanvas2(){
        //用canvas生成图片
        let canvas = document.createElement("canvas");
        let ctx = canvas.getContext('2d')
        canvas.width = 300
        canvas.height = 300
        //制作矩形
        ctx.fillStyle = "gray";
        ctx.fillRect(0, 0, 300, 300)
        //设置文字
        ctx.fillStyle = "white";
        ctx.font = 'normal 3px "楷体"'
        ctx.strokeText('furnace', 0, 2)

        //生成图片
        let url = canvas.toDataURL('image/png');
        //将图片构建到纹理中
        let geometry1 = new THREE.PlaneGeometry(15, 10)
        let material1 = new THREE.MeshBasicMaterial({
            map: new THREE.TextureLoader().load(url),
            side: THREE.DoubleSide,
            opacity: 1
        })
        let rect = new THREE.Mesh(geometry1, material1)
        rect.position.set(0, 0, 25.1)
        rect.rotateY(-Math.PI/2)
        this.config.scene.add(rect)
    }
    //获取与射线相交的对象数组
    getIntersects(event) {
        event.preventDefault();// 阻止默认的点击事件执行, https://developer.mozilla.org/zh-CN/docs/Web/API/Event/preventDefault
        //console.log("eventModel.clientX:" + eventModel.clientX);
        //console.log("eventModel.clientY:" + eventModel.clientY);

        //声明 rayCaster 和 mouse 变量
        let rayCaster = new THREE.Raycaster();
        let mouse = new THREE.Vector2();
        let canvas=this.config.renderer.domElement;
        //通过鼠标点击位置，计算出raycaster所需点的位置，以屏幕为中心点，范围-1到1
        mouse.x = ((event.clientX - canvas.getBoundingClientRect().left) / canvas.offsetWidth) * 2 - 1;
        mouse.y = -((event.clientY - canvas.getBoundingClientRect().top) / canvas.offsetHeight) * 2 + 1; //这里为什么是-号，没有就无法点中

        //通过鼠标点击的位置(二维坐标)和当前相机的矩阵计算出射线位置
        rayCaster.setFromCamera(mouse, this.config.cameraObject);

        //获取与射线相交的对象数组， 其中的元素按照距离排序，越近的越靠前。
        //+true，是对其后代进行查找，这个在这里必须加，因为模型是由很多部分组成的，后代非常多。
        let intersects = rayCaster.intersectObjects(this.config.scene.children, true);

        //返回选中的对象
        return intersects;
    }
}
export default  starThreejs;